#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>

#define ERRLOG(errmsg) do{\
	perror(errmsg);\
	printf("%s:%d\n",__func__,__LINE__);\
}while(0)
#define textlen 128

 //pthread_create 所使用  
typedef struct{
    char type;//传参:  1注册 2登陆 3增加 4删除 5修改 6查找
    char text[textlen];
}msg_t;

msg_t msg;
int msglen = sizeof(msg_t);
int sockfd;

char user_information[][16] = {"name","passwd","mod","id",\
                            "age","sex","wages","department"};
char mod = 0;//'0'普通用户 '1'管理员
char gname[32] = {0};
int gid = 0;

//注册
int do_register();
//登录
int do_login();
//查找
int user_info_find();
//修改
int user_info_modify(int);
//历史
int user_history();

//增加 
int root_add_user();
int root_delete();
int root_modify(); 
int root_find();
int root_history();

int uadd(char *buf);
int ufind(int id);
int udelete(int id);
int umodify(int id,int type);//1-8信息类型 
int uhistory(const char *name,int num);//1-8信息类型 

int main (int argc, char const *argv[])
{
	if(argc < 3)
	{
		fprintf(stderr,"Usage: %s <ip> <port>\n",argv[0]);
		exit(1);
	}
	struct sockaddr_in serveraddr;
	socklen_t addrlen = sizeof(struct sockaddr_in);
	
	//创建套接字
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		ERRLOG("socket error");
	}	
	//填充网络信息结构体
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	serveraddr.sin_port = htons(atoi(argv[2]));
	//发送客户端连接请求
	if(connect(sockfd,(struct sockaddr *)&serveraddr, addrlen) == -1)
	{
		ERRLOG("connect error");
	}
	
	//通信
    char choose;
	//---------------------注册/登陆---------------
	while(1)
    {
        printf("--------------------------\n");
        printf("|  1.注册 2.登陆 3.退出  |\n");
        printf("--------------------------\n");
        printf(">>");
        scanf("%c",&choose);
        getchar();
        switch(choose)
        {
        case '1':do_register();break;
        case '2':if(do_login()){goto app;}break;
        case '3':exit(1);break;
        default:puts("输入有误，请重试..");
        }
    }
//----------------------------------NUM---------------------------------
app:
    if(mod == '0')
    while(1)
    {
        printf("---------------------------------------------\n");
        printf("|  1.查询个人信息 2.修改密码 3.修改个人信息 |\n");
        printf("|  4.查询历史记录                    5.退出 |\n");
        printf("---------------------------------------------\n");
        printf(">>");
        scanf(" %c",&choose);
        getchar();
        switch(choose)
        {
        case '1':user_info_find();break;
        case '2':user_info_modify(2);break;
        case '3':user_info_modify(0);break;
        case '4':user_history();break;
        case '5':exit(1);break;
        default:puts("输入有误，请重试..");
        }
    }
    else if (mod == '1')
    while(1)
    {
        printf("------------------------------------------\n");
        printf("|  1.添加用户 2.删除用户 3.修改用户信息  |\n");
        printf("|  4.查询用户信息   5.查询历史   6.退出  |\n");
        printf("------------------------------------------\n");
        printf(">>");
        scanf(" %c",&choose);
        getchar();
        switch(choose)
        {
        case '1':root_add_user();break;
        case '2':root_delete();break;
        case '3':root_modify();break;
        case '4':root_find();break;
        case '5':root_history();break;
        case '6':exit(1);break;
        default:puts("输入有误，请重试..");
        }

    }
    else
        puts("权限错误，请联系管理员");
    return 0;
}

//=========================函数实现============================
//--------------------注册--------------------
int do_register()
{
    puts("注册：");
    char name[32] = {0};
    printf("    姓名：");
    scanf("%s",name);
    char passwd[32] = {0};
    printf("    密码：");
    scanf("%s",passwd);
    getchar();

    msg.type = 1;
    memset(msg.text,0,textlen);
    sprintf(msg.text,"%s:%s",name,passwd);
	
    if(send(sockfd, &msg, msglen, 0) == -1)
	{
		ERRLOG("send error");
	}
	if(recv(sockfd, &msg, msglen, 0) == -1)
	{
		ERRLOG("recv error");
	}
    printf("server:%d-%s\n",msg.type,msg.text);
    if(msg.type == 0)
    {
        printf("注册成功！\n");
        return 1;
    }
    else 
    {
        printf("该用户名已被占用，请重试\n");
        return 0;
    }
}
//---------------------登陆----------------------
int do_login()
{
    puts("登陆：");
    char name[32] = {0};
    printf("    姓名：");
    scanf("%s",name);
    char passwd[32] = {0};
    printf("    密码：");
    scanf("%s",passwd);
    getchar();

    msg.type = 2;
    memset(msg.text,0,textlen);
    sprintf(msg.text,"%s:%s",name,passwd);

    if(send(sockfd, &msg, msglen, 0) == -1)
	{
		ERRLOG("send error");
	}
	if(recv(sockfd, &msg, msglen, 0) == -1)
	{
		ERRLOG("recv error");
	}
    printf("server:%d-%s\n",msg.type,msg.text);
    if(msg.type == 0)
    {
        mod = *msg.text;
        strtok(msg.text," ");
        gid = atoi(strtok(NULL," ")); 
        strcpy(gname,name);
        if(mod == '0')
        {
            printf("普通用户");
        }
        else if(mod == '1')
        {
            printf("管理员");
        }
        printf("登陆成功！\n");
        return 1;
    }
    else 
    {
        printf("用户名或密码有误，请重试\n");
        return 0;
    }
}
//------------------------普通用户-----------------------
//用户查询自己信息
int user_info_find()
{
    return ufind(gid);
}

//用户根据id修改
int user_info_modify(int type)//参数：1-8 8个信息类型 0选择
{
    if(type == 0)
    {
        char choose;
        printf("可修改的选项如下：\n");
        printf("1.姓名\n");
        printf("2.年龄\n");
        printf("3.性别\n");
        printf(">>");
        scanf("%c",&choose);
        getchar();
        switch(choose)
        {
            case '1':umodify(gid,1);break;
            case '2':umodify(gid,5);break;
            case '3':umodify(gid,6);break;
            default:puts("输入有误..\n");break;
        }
    }
    else
    {
        umodify(gid,2);
    }
    return 1;
}
int user_history()
{
    return uhistory(gname,0);
}
//------------------------管理员---------------------
int root_add_user()
{
    int i;
    char buf[128] = {0};
    puts("输入要添加的用户的全部信息：");
    for(i = 0;i < (int)(sizeof(user_information)/16);i++)
    {
        printf("%s:",user_information[i]);
        scanf(" %s",buf+strlen(buf));
        getchar();
        strcat(buf," ");
    }
    return uadd(buf);
}

int root_find()
{
    int id;
    printf("待查询用户id(工号)(0查找全部):\n");
    scanf("%d",&id);
    getchar();
    return ufind(id);
}

int root_delete()
{
    int id;
    printf("待删除用户id(工号)：");
    scanf("%d",&id);
    getchar();
    return udelete(id);
}
int root_modify()
{
    
    int choose,id;
    printf("待修改用户id(工号)：");
    scanf("%d",&id);
    getchar();
    ufind(id);
    printf("可修改的选项如下：\n");
    printf("1.姓名 2.密码 3.权限 4.工号\n5.年龄 6.性别 7.工资 8.部门\n");
    printf(">>");
    scanf("%d",&choose);
    if((choose>0) && (choose<9))
    {
        return umodify(id,choose);
    }
    else
    {
        puts("输入有误..\n");
        return 0;    
    }
}
int root_history()
{
    int num;
    printf("查询数量:\n");
    scanf("%d",&num);
    getchar();
    return uhistory("0",num);
}

//==========================调用=========================
int ufind(int id)//0查询所有
{
    msg.type = 6;
    memset(msg.text,0,textlen);
    sprintf(msg.text,"%s:%d",gname,id);

    if(send(sockfd, &msg, msglen, 0) == -1)
	{
		ERRLOG("send error");
	}
    if(id != 0)//查一个
    {
	    if(recv(sockfd, &msg, msglen, 0) == -1)
	    {
		    ERRLOG("recv error");
    	}
        if(msg.type == 0)
        {
            printf("    name    : %s\n",strtok(msg.text," "));
            printf("   passwd   : %s\n",strtok(NULL," "));
            printf("    mod     : %s\n",strtok(NULL," "));
            printf("    id      : %s\n",strtok(NULL," "));
            printf("    age     : %s\n",strtok(NULL," "));
            printf("    sex     : %s\n",strtok(NULL," "));
            printf("   wages    : %s\n",strtok(NULL," "));
            printf(" department : %s\n",strtok(NULL," "));
            if(recv(sockfd, &msg, msglen, 0) == -1)
	        {
		        ERRLOG("recv error");
    	    }
            //printf("type = %d\n",msg.type);
            //终止信号
            return 1;
        }
        else
        {
            printf("查找完毕..\n");
            return 0;
        }
    }
    else//全查
    {
        printf("name    passwd  mod   id    age     sex     wages  department\n");
        while(1)
        {
            if(recv(sockfd, &msg, msglen, 0) == -1)
	        {
    		    ERRLOG("recv error");
    	    }
            if(msg.type == 0)
            {
                printf("%-8s",strtok(msg.text," "));
                printf("%-8s",strtok(NULL," "));
                printf(" %s ",strtok(NULL," "));
                printf(" %6s ",strtok(NULL," "));
                printf("%s   ",strtok(NULL," "));
                printf("%s   ",strtok(NULL," "));
                printf("%s   ",strtok(NULL," "));
                printf("%s\n",strtok(NULL," "));
            }
            else
            {
                printf("查找完毕..\n");
                return 1;
            }
        }
    }
}

int umodify(int id,int type)//参数：id ,1-8信息类型 
{
    char buf[32] = {0};
    printf("修改为：");
    scanf("%s",buf);
    getchar();
    msg.type = 5;
    memset(msg.text,0,textlen);
    sprintf(msg.text,"%s:%d:%s:%s",gname,id,user_information[type-1],buf);

    if(send(sockfd, &msg, msglen, 0) == -1)
	{
		ERRLOG("send error");
	}
    if(recv(sockfd, &msg, msglen, 0) == -1)
	{
		ERRLOG("recv error");
	}
    if(msg.type == 0)
    {
        printf("修改成功！\n");
        return 1;
    }
    else
    {
        printf("修改失败，请重试..\n");
        return 0;
    }
}

int udelete(int id)
{
    msg.type = 4;
    memset(msg.text,0,textlen);
    sprintf(msg.text,"%s:%d",gname,id);

    if(send(sockfd, &msg, msglen, 0) == -1)
	{
		ERRLOG("send error");
	}
    if(recv(sockfd, &msg, msglen, 0) == -1)
	{
		ERRLOG("recv error");
	}
    if(msg.type == 0)
    {
        printf("删除成功！\n");
        return 1;
    }
    else
    {
        printf("删除失败，请重试..\n");
        return 0;
    }
}

int uadd(char *buf)//buf要求用‘ ’分割数据类型
{
    msg.type = 3;
    memset(msg.text,0,textlen);
    sprintf(msg.text,"%s:%s",gname,buf);

    if(send(sockfd, &msg, msglen, 0) == -1)
	{
		ERRLOG("send error");
	}
    if(recv(sockfd, &msg, msglen, 0) == -1)
	{
		ERRLOG("recv error");
	}
    if(msg.type == 0)
    {
        printf("添加成功！\n");
        return 1;
    }
    else
    {
        printf("添加失败，请重试..\n");
        return 0;
    }
}

int uhistory(const char *dest_name,int num)//dest_name,num = 0全部查找
{
    msg.type = 7;
    memset(msg.text,0,textlen);
    sprintf(msg.text,"%s:%s:%d",gname,dest_name,num);
    if(send(sockfd, &msg, msglen, 0) == -1)
	{
		ERRLOG("send error");
	}

    printf("time                user        action\n");
        while(1)
        {
            if(recv(sockfd, &msg, msglen, 0) == -1)
	        {
    		    ERRLOG("recv error");
    	    }
            if(msg.type == 0)
            {
                printf("%-20s,%-8s, %s ",strtok(msg.text,"//"),strtok(NULL,"//"),strtok(NULL,"//"));
                putchar(10);
            }
            else
            {
                printf("查找完毕..\n");
                return 1;
            }
        }

}
